<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
   Function.prototype.call = function (thisObj, ...args) {
      console.log('call')
      // return this(...args)

      // 处理thisObj的特殊情况
      if (thisObj===undefined || thisObj===null) {
        // return this(...args)
        thisObj = window
      }

      // 将当前函数添加为thisObj的临时方法
      thisObj.tempFn = this
      // 通过thisObj来调用这个方法  => this就变为thisObj
      const result = thisObj.tempFn(...args)
      // 删除临时方法
      delete thisObj.tempFn
      // 返回方法执行的结果
      return result
   }

   Function.prototype.apply = function (thisObj, args) {
    console.log('apply')
    return this.call(thisObj, ...args)
   }

  // 返回一个新的函数, 新函数内部会调用原函数, 并指定函数中的this为bind的第一个参数
  // 原函数的实参: 优选考虑bind指定的参数, 其次考虑新函数调用指定的参数
  Function.prototype.bind = function (thisObj, ...args) {
    console.log('bind')
    return (...args2) => {
      return this.call(thisObj, ...args, ...args2)
    }
  }

   // 对象快照: 对象使用时的样子
  </script>

  <script>
    var m = 2
    function fn(a, b) {
      console.log(this, a, b);
      return a + b
    }
    const obj = {m: 1}

    // console.log(fn.call(obj, 2, 3))
    // console.log(fn.call(undefined, 2, 3))
    // console.log(fn.call(null, 2, 3))
    // console.log(fn.apply(obj, [2, 3]))

    console.log(fn.bind(obj)(1, 2))
    console.log(fn.bind(obj, 3)(1, 2))
    console.log(fn.bind(obj, 3, 4)(1, 2))

    
  </script>
</body>
</html>